/*
 * Copyright (c) 2007 Thomas Fors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// =======================================================
// Color Utility Functions
// =======================================================

// -------------------------------------------------------
// ProPhotoRGBColor()
// Constructor
// -------------------------------------------------------
function ProPhotoRGBColor() {
	// ProPhotoRGB specification from icc file
	this.vR = new Vector1x3(0x0CC34/0x10000, 0x049BD/0x10000, 0x00000/0x10000); // red
	this.vG = new Vector1x3(0x0229C/0x10000, 0x0B63E/0x10000, 0x00000/0x10000); // green
	this.vB = new Vector1x3(0x00806/0x10000, 0x00006/0x10000, 0x0D32D/0x10000); // blue
	this.vW = new Vector1x3(0x0F6D6/0x10000, 0x10000/0x10000, 0x0D32C/0x10000); // white
	this.gamma = 461/256;
	
	// Compute RGB/XYZ Conversion Matrix
	var vS = (new Matrix3x3(this.vR, this.vG, this.vB)).Inverse().Multiply(this.vW);
	this.M = new Matrix3x3(this.vR.Multiply(vS.a11), this.vG.Multiply(vS.a12), this.vB.Multiply(vS.a13));
}

// -------------------------------------------------------
// SetRGB()
// -------------------------------------------------------
ProPhotoRGBColor.prototype['SetRGB'] = function (r, g, b) {
	this.R = r;
	this.G = g;
	this.B = b;
	
	this.ComputeXYZ();
	this.Computexy();
	this.ComputeLab();
	this.ComputeLuv();
	this.ComputeCHS();
}

// -------------------------------------------------------
// ComputeXYZ()
// -------------------------------------------------------
ProPhotoRGBColor.prototype['ComputeXYZ'] = function () {
	// Convert to linear, normalized rgb
	var R = Math.pow( (this.R/255), this.gamma);
	var G = Math.pow( (this.G/255), this.gamma);
	var B = Math.pow( (this.B/255), this.gamma);
	var RGB = new Vector1x3(R, G, B);
	
	// Convert to CIE XYZ
	var XYZ = this.M.Multiply(RGB);
	this.X = XYZ.a11;
	this.Y = XYZ.a12;
	this.Z = XYZ.a13;
}

// -------------------------------------------------------
// Computexy()
// -------------------------------------------------------
ProPhotoRGBColor.prototype['Computexy'] = function () {
	// Compute x,y chromaticities
	this.x = this.X / (this.X+this.Y+this.Z);
	this.y = this.Y / (this.X+this.Y+this.Z);
}

// -------------------------------------------------------
// ComputeLab()
// -------------------------------------------------------
ProPhotoRGBColor.prototype['ComputeLab'] = function () {
	// Compute CIE L*a*b*
	var E = 216/24389;
	var K = 24389/27;
	
	var x2 = this.X/this.vW.a11;
	var y2 = this.Y/this.vW.a12;
	var z2 = this.Z/this.vW.a13;
	
	if ( x2 > E )
		Fx = Math.pow(x2, 1/3);
	else
		Fx = (K*x2 + 16) / 116;
	
	if ( y2 > E )
		Fy = Math.pow(y2, 1/3);
	else
		Fy = (K*y2 + 16) / 116;
	
	if ( z2 > E )
		Fz = Math.pow(z2, 1/3);
	else
		Fz = (K*z2 + 16) / 116;
	
	if ( y2 > E )
		this.L = 116*Fy-16;
	else
		this.L = K*y2;
	this.a = 500*(Fx-Fy);
	this.b = 200*(Fy-Fz);
}

// -------------------------------------------------------
// ComputeLuv()
// -------------------------------------------------------
ProPhotoRGBColor.prototype['ComputeLuv'] = function () {
	// Compute u' and v'
	this.up = 4*this.X / (this.X + 15*this.Y + 3*this.Z);
	this.vp = 9*this.Y / (this.X + 15*this.Y + 3*this.Z);
	
	// Compute ur' and vr' (u' and v' of reference white)
	var urp = 4*this.vW.a11 / (this.vW.a11 + 15*this.vW.a12 + 3*this.vW.a13);
	var vrp = 9*this.vW.a12 / (this.vW.a11 + 15*this.vW.a12 + 3*this.vW.a13);
	
	// Compute CIE L*u*v*
	this.u = 13 * this.L * (this.up - urp); // u*
	this.v = 13 * this.L * (this.vp - vrp); // v*
}

// -------------------------------------------------------
// ComputeCHS()
// -------------------------------------------------------
ProPhotoRGBColor.prototype['ComputeCHS'] = function () {
	this.C = Math.sqrt( (this.a*this.a + this.b*this.b), 2 );	// chroma
	this.H = Math.atan2(this.a, this.b) * 180 / Math.PI;		// hue
	this.S = this.C / this.L;									// saturation
}
